#!/usr/bin/python
#coding:utf-8
__author__ = "王勇"
import os
import time

class SocketBit(object):
    '''
    1、读入二进制位图并格式化位图
    2、读入8583报文体报文，报文内容不能包含换行
    3、从本目录读取银联规范8583.conf
    '''
    def __init__(self):
        '''
        初始化
        '''
        self.conf_dir = os.path.dirname(__file__)
        self.conf_file = self.conf_dir + "\\8583.conf"
        self.word_bit = ""
        self.word_msgreq = ""

    def _convert_to_bin(self,data):
        '''
        16进制转二进制
        :param data:
        :return:
        '''
        if " " in data:     #去空格
            data = data.replace(" ", "")
        if "\\x" in data:       #去\\x
            data = data.replace("\\x", "")
        print("处理后的十六进制位图：【%s】"% data)
        bina = bin(int(data,16))        #转二进制bin
        return bina[2:]         #切片，从第二位开始取值

    def _convert_to_str(self,request_data):
        '''
        十六进制转字符串，注意报文中的空格以及\\x需要去除
        :param request_data:
        :return:
        '''
        if " " in request_data:     #去空格
            request_data = request_data.replace(" ","")
        if "\\x" in request_data:   #去转义\
            request_data = request_data.encode("utf-8").decode("unicode_escape")  # 此处必须使用unicode_escape取内存值，否则单反斜杠会被转义后赋值
        stra = str(request_data)
        return str(stra)

    def _bit_map(self):
        '''
        读入二进制位图并做格式化
        f2 3e 40 81 8a d0 80 98 00 00      00 00 10 00 00 20
        \xf2\x3e\x40\x81\x8a\xd0\x80\x98\x00\x00\x00\x00\x10\x00\x00\x20
        f23e40818ad080980000000010000020
        :return:
        '''
        while len(self.word_bit) == 0:
            self.word_bit = input("请输入位图，二进制、十六进制均可:\n")     #python2使用raw_input

        #判断是否为16进制
        if ("f" in self.word_bit) or ("e" in self.word_bit)  or ("2" in self.word_bit):
            print("您输入的位图为16进制，后台正在努力转成二进制位图，请稍后。。。。")
            time.sleep(1)
            self.word_bit = self._convert_to_bin(self.word_bit)     #十六进制转二进制
            print("生成的二进制位图：【%s】"%(self.word_bit))

        #获取二进制1位置
        li = []
        for i,j in enumerate(self.word_bit,1):
            if j=='1':
                li.append(i)
        #判断第一位是否为1
        if li[0] == 1:
            print("位图第一位为1，则域66到128有值")
        word = str(list(li))
        print("生成8583各域:\n%s"%(word))
        # 过滤生成的位图域信息
        word = word.replace(' ','')     #替换空格
        word = word.replace('[','')     #替换[
        word = word.replace(']','')     #替换]
        self.word_bitmap = word.split(',')     #过滤掉逗号
        #print(self.word_bitmap)
        return self.word_bitmap

    def _request(self):
        '''
        读入8583报文体，上送16进制、十进制均可
        \x31\x36\x36\x32\x32\x36\x33\x30\x32\x36
        16622630261049471
        :return:
        '''
        while len(self.word_msgreq) == 0:
            self.word_msgreq = input("请输入8583报文送十六进制、十进制均可（无8583报文头、无换行）:\n")

        #判断是否为8583报文
        if ("\\x30" in self.word_msgreq) or ("\\x31" in self.word_msgreq):
            print("请求报文为十六进制，正在转成十进制")
            self.word_msgreq = self._convert_to_str(self.word_msgreq)
            print("生成的十进制请求报文：【%s】"%(self.word_msgreq))
        #print(self.word_msg)
        return self.word_msgreq

    def _bank_rule(self):
        '''
        读入银联规范接口文件8583.conf
        :return:
        '''
        f = open(self.conf_file, "r", encoding="utf-8")
        date = f.read()
        f.close()
        self.bank_area = date.split('\n')
        #print(self.bank_area)
        return self.bank_area

    def _write_text(self):
        filen = self.conf_dir + "/8583_Result_"
        writetxt = input("请输入要保存的文件名称：")
        filename = filen + writetxt + ".txt"
        fw = open(filename,"a")
        print("8583报文解析后文件名：" + filename)
        return fw


    def main(self):
        word_bitmap = self._bit_map()
        word_reqmsg = self._request()
        bank_area = self._bank_rule()
        write_nanl = self._write_text()
        print("---------8583报文解析如下--------------")
        for item in word_bitmap:
            for item_table in bank_area:
                info = item_table.split('\t')   #tab键分割银联规范接口
                #判断十进制位图是否存在于银联接口域中
                if item == info[0]:
                    if '/' in info[2]:
                        #判断变长，目前银联最大3位变长
                        len_list = info[2].split('/')
                        if len_list[0] == "2" :
                            str_var = "LLVAR"
                        elif len_list[0] == "3" :
                            str_var = "LLLVAR"
                        else:
                            str_var = "LLLLVAR"
                        #对报文进行切片
                        len_int = int(len_list[0])
                        lens = int( word_reqmsg[0:len_int] )       #获取变长值
                        #获取字段值
                        word_reqmsg = word_reqmsg[len_int:]
                        word1 = word_reqmsg[0:lens]
                        print("b"+item," ",info[1]," ",str_var," ",info[2]," ",'[',lens,']'," ",word1)
                        # txt = "b" + item+ " "+ info[1]+ " "+ str_var+ " "+ info[2]+ " "+ '[' + str(lens) + ']'+ " "+ word1+ "\n"
                        # print(txt)
                        write_nanl.write("b" + item+ " "+ info[1]+ " "+ str_var+ " "+ info[2]+ " "+ '[' + str(lens) + ']'+ " "+ '[' +word1+ ']'+ "\n")
                        word_reqmsg = word_reqmsg[lens:]
                    else:       #定长
                        len1 = int(info[2])
                        word1 = word_reqmsg[0:len1]
                        str_var = "DATA"
                        print("b"+item," ",info[1]," ",str_var," ",info[2]," ",'[',len1,']'," ",word1)
                        write_nanl.write("b" + item + " " + info[1] + " " + str_var + " " + info[2] + " " + '[' + str(len1) + ']' + " " + '[' + word1 + ']' + "\n")
                        word_reqmsg = word_reqmsg[len1:]
        write_nanl.close()      #关闭写句柄

if __name__ == "__main__":
    socket = SocketBit()
    socket.main()